package com.tea.room.service.wechat.impl;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.security.KeyStore;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tea.room.dao.WeChatTokenDao;
import com.tea.room.dao.tea.HouseInfoDao;
import com.tea.room.dao.tea.SelectionDao;
import com.tea.room.dao.tea.TeaOrderDao;
import com.tea.room.model.Return;
import com.tea.room.model.WeChatToken;
import com.tea.room.model.tea.HouseInfo;
import com.tea.room.model.tea.Selection;
import com.tea.room.model.tea.TeaOrder;
import com.tea.room.model.xmlBean.Xml2Map;
import com.tea.room.service.door.DoorService;
import com.tea.room.service.wechat.PayService;
import com.tea.room.service.wechat.WeChatService;
import com.tea.room.util.AESUtil;
import com.tea.room.util.ConfigUtil;
import com.tea.room.util.DateUtils;
import com.tea.room.util.JsonUtil;

@Service
public class PayServiceImpl implements PayService {

    private static Logger logger = LoggerFactory.getLogger(PayServiceImpl.class);

    private static Properties wechat = ConfigUtil.getProperties("wechat.properties");

    @Autowired
    private WeChatTokenDao weChatTokenDao;

    @Autowired
    private TeaOrderDao teaOrderDao;

    @Autowired
    private SelectionDao selectionDao;
    
    @Autowired
    private HouseInfoDao houseInfoDao;
    
    @Autowired
    private DoorService doorService;
    
    @Autowired
    private WeChatService weChatService;

    @Override
    public Return getPayParams(String out_trade_no, String total_fee, String openid) {
        Return rn = new Return();
        logger.info("支付下单入参，订单号：" + out_trade_no + "金额：" + total_fee);
        try {
            if(out_trade_no == null || out_trade_no.equals("")){
                rn.setIsSuccessflag(false);
                rn.setMessage("out_trade_no 为空");
                return rn;
            }
            if(total_fee == null || total_fee.equals("")){
                rn.setIsSuccessflag(false);
                rn.setMessage("total_fee 为空");
                return rn;
            }
            Map<String, Object> param = getPrepayid(out_trade_no, total_fee, openid);
            rn.setIsSuccessflag(true);
            rn.setDataMap(param);
        } catch (Exception e) {
            rn.setIsSuccessflag(false);
            rn.setMessage("微信支付异常！");
            e.printStackTrace();
        }
        return rn;
    }

    @Override
    public String weChatPayCallBack(HttpServletRequest request) {
        String reqXml = "<xml><return_code><![CDATA[%1$s]]></return_code><return_msg><![CDATA[%2$s]]></return_msg></xml>";
        String returnMsg = "";
        InputStream is = null;
        ByteArrayOutputStream baos = null;
        try {
            is = request.getInputStream();
            baos = new ByteArrayOutputStream();
            byte[] buff = new byte[1024];
            int length = 0;
            while ((length = is.read(buff)) != -1) {
                baos.write(buff, 0, length);
            }
            String result = new String(baos.toByteArray(), "UTF-8");
            logger.info("支付回调结果：" + result);
            Map<String, Object> map = WeChatUtil.xmlToMap(result);
            boolean isSuccess = false;
            if ("SUCCESS".equals(map.get("result_code"))) {
                logger.info("微信支付----返回成功");
                Map<String, Object> mapSign = new HashMap<String, Object>();
                mapSign.putAll(map);
                mapSign.remove("sign");
                String sign = WeChatUtil.getPayCustomSign(mapSign, wechat.getProperty("KEY"));
                logger.info("微信支付---- 验签sign：" + sign);
                if (map.get("sign").equals(sign)) {
                    logger.info("微信支付---验签成功");
                    isSuccess = true;
                    returnMsg = String.format(reqXml, "SUCCESS", "OK");
                } else {
                    logger.info("微信支付---验签失败");
                    returnMsg = String.format(reqXml, "ERROR", "FAIL");
                }
            } else {
                logger.info("微信支付失败--错误信息：" + map.get("err_code_des"));
                returnMsg = String.format(reqXml, "ERROR", "FAIL");
            }
            TeaOrder order = new TeaOrder();
            order.setMdf_date(new Date());
            order.setSerno(String.valueOf(map.get("out_trade_no")));
            order.setOpenId((String)map.get("openid"));
            if (isSuccess) {
                // 1.修改订单状态
                order.setStatus("已支付");
                order.setPayStatus("Y");
                logger.info("修改订单状态开始");
                teaOrderDao.update(order);
                logger.info("修改订单状态结束");
                // 2.更新已预订时间段
                logger.info("更新已预订时间段信息开始");
                String flag = updateReserveTime(order);
                // 3.推送消息
                logger.info("更新已预订时间段信息flag：" + flag);
                if(flag.equals("-1")){//时段已被预定，退款，并通知用户
                	logger.info("时段已被预定，退款，并通知用户flag：" + flag);
                    payRefund(String.valueOf(map.get("out_trade_no")), String.valueOf(map.get("settlement_total_fee")));
                    // 修改订单状态
                    order.setStatus("已申请退款");
                    order.setPayStatus("已申请退款");
                    teaOrderDao.update(order);
                    sendFailMesg(map.get("openid"));
                }else{
                    //TODO 获取门锁
                    Integer password = (int) (Math.random() * 899999 + 100000);
                    logger.info("获取门锁密码：" + password);
                    Map<String, Object> param = new HashMap<String, Object>();
                    TeaOrder query = teaOrderDao.query(order);
                    //目前就一把门锁暂时写死
                    //多把门锁根据 茶室ID查询茶室详情获取
                    //HouseInfo info = new HouseInfo();
                    //String teaCode = teaOrderDao.query(order).getTeaCode();
                    //info.setTeaCode(teaCode);
                    //houseInfoDao.query(info);
                    param.put("lockId", 3615);
                    param.put("password", password);// 密码，长度4-8位，一般为6位
                    Long start = query.getStart().getTime() - 10 * 60 * 1000;
                    Long end = query.getReminder().getTime();
                    param.put("validStart", start);//开始时间时间戳到毫秒
                    param.put("validUntil", end);//结束时间 时间戳到毫秒
                    Boolean ff = false;
                    do {
                        String post = doorService.onlinePassword(param);
                        ff = (Boolean)JsonUtil.jsonStrToJsonObject(post).get("success");
                    } while (!ff);
                    order.setPassword(String.valueOf(password));
                    // 更新门锁密码
                    teaOrderDao.update(order);
                    //获取用户微信数据
                    Return userInfo = weChatService.addUserInfo(map.get("openid")+"");
                    //通知用户
                    sendPaySuccessMesg(order, flag, map.get("total_fee"), map.get("openid"), String.valueOf(password));
                    //通知管理员
                    messageNotice(userInfo, query, password);
                }
            } else {
                order.setPayStatus("支付失败");
                teaOrderDao.update(order);
            }
        } catch (Exception e) {
            e.printStackTrace();
            returnMsg = String.format(reqXml, "ERROR", "FAIL");
        } finally {
            try {
                if (is != null)
                    is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (baos != null)
                    baos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return returnMsg;
    }
    
    /**
     * 客户预定成功，通知管理员
     * @param o
     * @return
     */
    public String messageNotice(Return userInfo, TeaOrder order, Integer password) {
        Map<String, Object> map = new HashMap<String, Object>();
        Map<String, Object> content = new HashMap<String, Object>();
        String[] admin = wechat.getProperty("ADMIN").split(",");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (int i = 0; i < admin.length; i++) {
            map.put("touser", admin[i]);
            map.put("msgtype", "text");
            Map<String, Object> dataMap = userInfo.getDataMap();
            content.put("content", "茶室预定成功! \n "
                    + "微  信  名：" + dataMap.get("nickname") + "\n "
                    + "用户来源：" + getChannel(dataMap.get("subscribe_scene").toString()) + "\n "
                    + "门锁密码：" + password + "\n "    
                    + "支付金额：" + order.getPrice() + "\n "
                    + "预定时间：" + sdf.format(order.getStart()) + " - " + sdf.format(order.getReminder()));
            map.put("text", content);
            // 组装模板消息数据
            logger.info("参数："+JsonUtil.mapToJsonObject(map).toJSONString());
            // 获取token拼接请求链接
            WeChatToken token = weChatTokenDao.queryWCToken();
            String url = wechat.getProperty("CUSTOM_MESG") + token.getAccess_token();
            com.tea.room.util.HttpClient client = com.tea.room.util.HttpClient.getInstance();
            // 请求接口
            client.sendHttpPost(url, JsonUtil.mapToJsonObject(map).toString(), "application/json");
        }
        return "suc";
    }
    /**
        ADD_SCENE_SEARCH                    公众号搜索，
        ADD_SCENE_ACCOUNT_MIGRATION         公众号迁移，
        ADD_SCENE_PROFILE_CARD              名片分享，
        ADD_SCENE_QR_CODE                   扫描二维码，
        ADD_SCENEPROFILE LINK               图文页内名称点击，
        ADD_SCENE_PROFILE_ITEM              图文页右上角菜单，
        ADD_SCENE_PAID                      支付后关注，
        ADD_SCENE_OTHERS                    其他
     * @return
     */
    public String getChannel(String channel){
        String ch = "";
        switch (channel) {
        case "ADD_SCENE_SEARCH":
            ch = "公众号搜索";
            break;
        case "ADD_SCENE_ACCOUNT_MIGRATION":
            ch = "公众号迁移";
            break;
        case "ADD_SCENE_PROFILE_CARD":
            ch = "名片分享";
            break;
        case "ADD_SCENE_QR_CODE":
            ch = "扫描二维码";
            break;
        case "ADD_SCENEPROFILE LINK":
            ch = "图文页内名称点击";
            break;
        case "ADD_SCENE_PROFILE_ITEM":
            ch = "图文页右上角菜单";
            break;
        case "ADD_SCENE_PAID":
            ch = "支付后关注";
            break;
        default:
            ch = "其他";
            break;
        }
        return ch;
    }

    /**
     * 获取prepayid
     * 
     * @param out_trade_no
     * @param total_fee
     * @return
     * @throws Exception
     */
    public Map<String, Object> getPrepayid(String out_trade_no, String total_fee, String openid) throws Exception {
        Map<String, Object> map = new HashMap<String, Object>();
        String nonceStr = UUID.randomUUID().toString().substring(0, 36).replace("-", "");
        String appid = wechat.getProperty("APPID");
        String mch_id = wechat.getProperty("MCH_ID");
        String trade_type = wechat.getProperty("TRADE_TYPE");
        String notify_url = wechat.getProperty("NOTIFY_URL");
        String spbill_create_ip = wechat.getProperty("SPBILL_CREATE_IP");
        long timestamp = System.currentTimeMillis() / 1000;
        map.put("appid", appid);
        map.put("mch_id", mch_id);
        map.put("nonce_str", nonceStr);
        map.put("body", "JSAPI");
        map.put("out_trade_no", out_trade_no);
        map.put("total_fee", total_fee);
        map.put("spbill_create_ip", spbill_create_ip);
        map.put("notify_url", notify_url);
        map.put("trade_type", trade_type);
        map.put("openid", openid);//openid前台传入
        String paySign = WeChatUtil.getPayCustomSign(map, wechat.getProperty("KEY"));
        map.put("sign", paySign);
        String xml = WeChatUtil.ArrayToXml(map);
        logger.info("微信支付---下单报文：" + xml);
        JSONObject result = WeChatUtil.sendWeChat(xml,wechat.getProperty("PREPAYID"));
        logger.info("微信支付---下单返回报文：" + result);
        JSONObject element = result.getJSONObject("xml");
        Object return_code = ((JSONArray) element.get("return_code")).get(0);
        Object prepayid = "";
        map.put("return_code", ((JSONArray) element.get("result_code")).get(0));
        if(return_code.equals("SUCCESS")){
            Object result_code = ((JSONArray) element.get("result_code")).get(0);
            if(result_code.equals("SUCCESS")){
                prepayid = ((JSONArray) element.get("prepay_id")).get(0);
                TeaOrder order = new TeaOrder();
                order.setMdf_date(new Date());
                order.setSerno(out_trade_no);
                order.setOpenId((String)map.get("openid"));
                order.setStatus("待支付");
                teaOrderDao.update(order);
            }else{
                map.put("return_msg", ((JSONArray) element.get("err_code_des")).get(0));
                return map;
            }
        }else{
            map.put("return_msg", ((JSONArray) element.get("return_msg")).get(0));
            return map;
        }
        map.put("timestamp", Long.valueOf(timestamp).toString());
        map.put("prepayid", prepayid);
        Map<String, Object> h5PayParams = WeChatUtil.getH5PayParams(map,wechat.getProperty("KEY"));
        return h5PayParams;
    }

    /**
     * 支付成功，给用户发送模板消息
     * 
     * @param price
     * @param touser
     */
    @Override
    public void sendPaySuccessMesg(TeaOrder order, String flag, Object price, Object touser, String password) {
        Map<String, Object> map = new HashMap<String, Object>();
        Map<String, Object> data = new HashMap<String, Object>();
        Map<String, Object> first = new HashMap<String, Object>();
        Map<String, Object> keyword1 = new HashMap<String, Object>();
        Map<String, Object> keyword2 = new HashMap<String, Object>();
        Map<String, Object> keyword3 = new HashMap<String, Object>();
        Map<String, Object> keyword4 = new HashMap<String, Object>();
        Map<String, Object> keyword5 = new HashMap<String, Object>();
        Map<String, Object> remark = new HashMap<String, Object>();
        TeaOrder teaOrder = teaOrderDao.query(order);
        HouseInfo info = new HouseInfo();
        info.setTeaCode(teaOrder.getTeaCode());
        HouseInfo houseInfo = houseInfoDao.query(info);
        logger.info("尊敬的 "+touser+" 客户，您预订的茶室支付成功通知！");
        // 组装模板消息数据
        first.put("color", "#000000");//字体颜色
        first.put("value", "尊敬的客户，您预订的茶室支付成功通知！");
        data.put("first", first);

        keyword1.put("color", "#173177");//字体颜色
        String address = houseInfo.getAddress();
        keyword1.put("value", address);//地址
        data.put("keyword1", keyword1);

        String[] interval = teaOrder.getTime_interval().split("-");
        String time = DateUtils.getToDay(0) + " " + interval[0] + ":00 - ";
        if(flag.equals("1")){
            time += DateUtils.afterday(new Date()) + " " + interval[1] + ":00";
        }else{
            time += DateUtils.getToDay(0) + " " + interval[1] + ":00";
        }
        keyword2.put("color", "#173177");//字体颜色
        keyword2.put("value", time);//时间
        data.put("keyword2", keyword2);

        Double d = Double.valueOf((String) price);
        String prices = new BigDecimal(d / 100).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
        keyword3.put("color", "#173177");//字体颜色
        keyword3.put("value", prices + "元");//金额
        data.put("keyword3", keyword3);

        keyword4.put("color", "#173177");//字体颜色
        keyword4.put("value", "支付成功");//状态
        data.put("keyword4", keyword4);
        
        keyword5.put("color", "#ff0000");//字体颜色
        keyword5.put("value", password);//门锁密码
        data.put("keyword5", keyword5);

        remark.put("color", "#000000");//字体颜色
        remark.put("value", "订单编号：" + teaOrder.getSerno());
        data.put("remark", remark);
        map.put("touser", touser);//用户id
        map.put("template_id", "zGkBSyp3n26UfUgrPxfAgXwew5Kl80ag0ygmGrie3JQ");//模板ID
        map.put("url", "");//点击模版消息跳转的地址
        map.put("data", data);
        // 获取token拼接请求链接
        WeChatToken token = weChatTokenDao.queryWCToken();
        String url = wechat.getProperty("SEND_MESG") + token.getAccess_token();
        com.tea.room.util.HttpClient client = com.tea.room.util.HttpClient.getInstance();
        // 请求接口
        client.sendHttpPost(url, JsonUtil.mapToJsonObject(map).toString(), "application/json");
    }
    
    @Override
    public void sendFailMesg(Object touser) {
        Map<String, Object> map = new HashMap<String, Object>();
        Map<String, Object> data = new HashMap<String, Object>();
        Map<String, Object> first = new HashMap<String, Object>();
        Map<String, Object> keyword1 = new HashMap<String, Object>();
        Map<String, Object> keyword2 = new HashMap<String, Object>();
        Map<String, Object> remark = new HashMap<String, Object>();
        // 组装模板消息数据
        first.put("color", "#000000");//字体颜色
        first.put("value", "预订失败通知");
        data.put("first", first);

        keyword1.put("color", "#173177");//字体颜色
        keyword1.put("value", "私茶");//地址
        data.put("keyword1", keyword1);

        keyword2.put("color", "#173177");//字体颜色
        keyword2.put("value", "由于其他用户已经成功预定改时段，暂时无法帮您完成预订");//时间
        data.put("keyword2", keyword2);

        remark.put("color", "#000000");//字体颜色
        remark.put("value", "请您返回重新预订，已支付费用将在24小时内退回您的账户，如有疑问请咨询13800000000");
        data.put("remark", remark);
        map.put("touser", touser);//用户id
        map.put("template_id", "3GSglSOGneS7e4-widJr9WcIvKv8Gs62bAk0dM-mVBA");//模板ID
        map.put("url", "");//点击模版消息跳转的地址
        map.put("data", data);
        System.out.println(map);
        // 获取token拼接请求链接
        WeChatToken token = weChatTokenDao.queryWCToken();
        String url = wechat.getProperty("SEND_MESG") + token.getAccess_token();
        com.tea.room.util.HttpClient client = com.tea.room.util.HttpClient.getInstance();
        // 请求接口
        client.sendHttpPost(url, JsonUtil.mapToJsonObject(map).toString(), "application/json");
    }

    /**
     * 更新预定时间段
     * 
     * @param order
     * @return
     */
    @Override
    public String updateReserveTime(TeaOrder order) {
        String flag = "0"; //成功，时间跨度没有两天
        Selection selection = new Selection();
        Selection selection2 = new Selection();
        TeaOrder query = teaOrderDao.query(order);
        String interval = query.getTime_interval();
        String[] split = interval.split("-");// 获取订单预定时段
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String startDay = sdf.format(query.getStart());//预定开始的日期
        String endDay = sdf.format(query.getReminder());//预定结束的日期
        String nowDay = sdf.format(new Date());//当天日期
        SimpleDateFormat sdf1 = new SimpleDateFormat("HH:mm:ss");
        String[] nowTime = sdf1.format(new Date()).split(":");//当前时间
        List<String> list = DateUtils.sortTime(Integer.valueOf(nowTime[0]), Integer.valueOf(nowTime[1]));//获取当前时间往后的时间节点
        int i = list.indexOf("00:00"); //获取零点坐标
        int s = list.indexOf(split[0]); //获取起始坐标
        int e = list.indexOf(split[1]); //获取截止坐标
        List<String> today = new ArrayList<String>();// 当天时段
        List<String> tomo = new ArrayList<String>();// 第二天时段
        String strToday = "";
        String strTomo = "";

        logger.info("零点坐标i:" + i + "---起始坐标s:" + s + "---截止坐标e:" + e );
        logger.info("startDay:" + startDay + "    endDay:" + endDay + "    nowDay:" + nowDay );
        
        //开始，结束时间都是当天    预定时段是当天
        if (startDay.equals(nowDay) && endDay.equals(nowDay)){
            today.addAll(list.subList(s, e+1));
        } 
        //开始不是当天，也不是当天  预定时段是第二天
        if (!startDay.equals(nowDay) && !endDay.equals(nowDay)){
            tomo.addAll(list.subList(s, e+1));
        } 
        //开始是当天，结束不是当天 预定时段跨今明两天
        if (startDay.equals(nowDay) && !endDay.equals(nowDay)) {
        	today.addAll(list.subList(s, i));
            tomo.addAll(list.subList(i, e+1));
        }
        
        logger.info("时段tomo:" + tomo);
        logger.info("时段today:" + today);
        
        //查询当天时段
        selection.setTeaCode(query.getTeaCode());
        selection.setSame_day(sdf.format(query.getCrt_date()));
        selection.setCrt_date(new Date());
        Selection s1 = selectionDao.query(selection);
        String old = "";
        if(s1 != null){
            old = s1.getSelection();
            logger.info("当天的预定时段:" + old);
        }
        //校验时段是否被预定成功
        for (int j = 0; j < today.size(); j++) {
            int indexOf = old.indexOf(today.get(j));
            strToday += "," + today.get(j);
            if(indexOf != -1){
                flag = "-1";
                logger.info("flag:" + flag);
                return flag;
            }
        }
        
        //更新当天时段
        if(today.size() > 0){
        	if(s1 == null){
        		logger.info("strToday:" + strToday);
        		selection.setSelection(strToday);
        		selectionDao.insert(selection);
        	}else{
        		logger.info("start old + today:" + old);
        		String temp = "";
        		for (String str : today) {
        		    temp += "," + str;
        		}
        		
        		logger.info("old + today:" + old + temp);
        		selection.setSelection(old + temp);
        		logger.info("selection:" + selection);
        		selectionDao.update(selection);
        	}
        }
        
        //查询明天的时段
        selection2.setTeaCode(query.getTeaCode());
        selection2.setSame_day(DateUtils.afterday(query.getCrt_date()));
        selection2.setCrt_date(new Date());
        Selection s2 = selectionDao.query(selection2);
        
        String old2 = "";
        if(s2 != null){
            old2 = s2.getSelection();
            logger.info("第二天的预定时段:" + old2);
        }
        //校验时段是否被预定成功
        for (int j = 0; j < tomo.size(); j++) {
            int indexOf = old2.indexOf(tomo.get(j));
            strTomo += "," + tomo.get(j);
            if(indexOf != -1){
                flag = "-1";
                logger.info("flag:" + flag);
                return flag;
            }
        }
        
        //更新明天的时段
        if(tomo.size() > 0){
            if(s2 == null){
            	logger.info("strTomo:" + strTomo);
            	selection2.setSelection(strTomo);
                selectionDao.insert(selection2);
            }else{
                old = s2.getSelection();
                logger.info("start old + tomo:" + old);
                String temp = "";
                for (String str : tomo) {
                    temp +=  "," + str;
    			}
                logger.info("old + tomo:" + old + temp);
                selection2.setSelection(old + temp);
                logger.info("selection2:" + selection2);
                selectionDao.update(selection2);
            }
            flag = "1";
        }
        logger.info("end flag:" + flag);
        return flag;
    }

    @Override
    public Return queryOrder(HttpServletRequest request) {
        Return rn = new Return();
        String out_trade_no = request.getParameter("out_trade_no");
        if(out_trade_no == null || out_trade_no.equals("")){
            rn.setIsSuccessflag(false);
            rn.setMessage("out_trade_no 为空");
            return rn;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        String nonceStr = UUID.randomUUID().toString().replace("-", "").substring(0, 32);
        String appid = wechat.getProperty("APPID");
        String mch_id = wechat.getProperty("MCH_ID");
        map.put("appid", appid);// 公众账号ID
        map.put("mch_id", mch_id);// 商户号
        map.put("nonce_str", nonceStr);// 随机字符串
        map.put("sign_type", "MD5");// 签名类型 
        map.put("out_trade_no", out_trade_no);// 商户订单号
        try {
            map.put("sign", WeChatUtil.getPayCustomSign(map, wechat.getProperty("KEY")));
        } catch (Exception e) {
            e.printStackTrace();
            rn.setIsSuccessflag(false);
            rn.setMessage(e.getMessage());
            return rn;
        }
        String xml = WeChatUtil.ArrayToXml(map);
        logger.info("微信支付---查询订单发送报文：" + xml);
        JSONObject result = WeChatUtil.sendWeChat(xml,wechat.getProperty("QUERYORDER"));
        logger.info("微信支付---查询订单返回报文：" + result);
        JSONObject element = result.getJSONObject("xml");
        Object return_code = ((JSONArray) element.get("return_code")).get(0);
        rn.setIsSuccessflag(false);
        if(return_code.equals("SUCCESS")){
            Object result_code = ((JSONArray) element.get("result_code")).get(0);
            if(result_code.equals("SUCCESS")){
                rn.setIsSuccessflag(true);
                rn.setMessage(((JSONArray) element.get("trade_state_desc")).get(0).toString());
                logger.info("微信支付---查询订单成功：" + ((JSONArray) element.get("trade_state_desc")).get(0));
            }else{
                rn.setMessage(((JSONArray) element.get("err_code_des")).get(0).toString());
                logger.info("微信支付---查询订单失败：" + ((JSONArray) element.get("trade_state_desc")).get(0));
            }
        }else{
            rn.setMessage(((JSONArray) element.get("return_msg")).get(0).toString());
            logger.info("微信支付---查询订单失败：" + ((JSONArray) element.get("trade_state_desc")).get(0));
        }
        return rn;
    }
    
    @Override
    public Return closeOrder(HttpServletRequest request) {
        Return rn = new Return();
        String out_trade_no = request.getParameter("out_trade_no");
        if(out_trade_no == null || out_trade_no.equals("")){
            rn.setIsSuccessflag(false);
            rn.setMessage("out_trade_no 为空");
            return rn;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        String nonceStr = UUID.randomUUID().toString().replace("-", "").substring(0, 32);
        String appid = wechat.getProperty("APPID");
        String mch_id = wechat.getProperty("MCH_ID");
        map.put("appid", appid);// 公众账号ID
        map.put("mch_id", mch_id);// 商户号
        map.put("nonce_str", nonceStr);// 随机字符串
        map.put("sign_type", "MD5");// 签名类型 
        map.put("out_trade_no", out_trade_no);// 商户订单号
        try {
            map.put("sign", WeChatUtil.getPayCustomSign(map, wechat.getProperty("KEY")));
        } catch (Exception e) {
            e.printStackTrace();
            rn.setIsSuccessflag(false);
            rn.setMessage(e.getMessage());
            return rn;
        }
        String xml = WeChatUtil.ArrayToXml(map);
        logger.info("微信支付---关闭订单发送报文：" + xml);
        JSONObject result = WeChatUtil.sendWeChat(xml,wechat.getProperty("CLOSEORDER"));
        logger.info("微信支付---关闭订单返回报文：" + result);
        JSONObject element = result.getJSONObject("xml");
        Object return_code = ((JSONArray) element.get("return_code")).get(0);
        rn.setIsSuccessflag(false);
        if(return_code.equals("SUCCESS")){
            Object result_code = ((JSONArray) element.get("result_code")).get(0);
            if(result_code.equals("SUCCESS")){
                rn.setIsSuccessflag(true);
                rn.setMessage("SUCCESS");
                logger.info("微信支付---关闭订单成功");
            }else{
                rn.setMessage(((JSONArray) element.get("err_code_des")).get(0).toString());
                logger.info("微信支付---关闭订单失败" + ((JSONArray) element.get("err_code_des")).get(0));
            }
        }else{
            rn.setMessage(((JSONArray) element.get("return_msg")).get(0).toString());
            logger.info("微信支付---关闭订单失败"  + ((JSONArray) element.get("return_msg")).get(0));
        }
        return rn;
    }
    
    @SuppressWarnings("deprecation")
    @Override
    public Return payRefund(String out_trade_no, String total_fee) throws Exception {
        Return rn = new Return();
        Map<String, Object> map = new HashMap<String, Object>();
        String nonceStr = UUID.randomUUID().toString().replace("-", "").substring(0, 32);
        String appid = wechat.getProperty("APPID");
        String mch_id = wechat.getProperty("MCH_ID");
        String notify_url = wechat.getProperty("REFUNDNOTIFY_URL");
        map.put("appid", appid);// 公众账号ID
        map.put("mch_id", mch_id);// 商户号
        map.put("nonce_str", nonceStr);// 随机字符串
        map.put("sign_type", "MD5");// 签名类型 
        map.put("total_fee", total_fee);// 订单金额
        map.put("refund_fee", total_fee);// 退款金额 
        map.put("out_trade_no", out_trade_no);// 商户订单号
        map.put("out_refund_no", new Date().getTime());// 商户退款单号 
        map.put("notify_url", notify_url);// 通知地址
        map.put("sign", WeChatUtil.getPayCustomSign(map, wechat.getProperty("KEY")));// 签名
        String xml = WeChatUtil.ArrayToXml(map);
        KeyStore keyStore  = KeyStore.getInstance("PKCS12");
        FileInputStream instream = new FileInputStream(new File(wechat.getProperty("PATH_P12")));//放退款证书的路径
        try {
            keyStore.load(instream, wechat.getProperty("MCH_ID").toCharArray());
        } finally {
            instream.close();
        }
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, wechat.getProperty("MCH_ID").toCharArray()).build();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
            sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        
        logger.info("微信支付---申请退款发送报文：" + xml);
        String result = "";
        try {
            HttpPost httpPost = new HttpPost(wechat.getProperty("REFUNDURL"));//退款接口
            System.out.println("executing request" + httpPost.getRequestLine());
            StringEntity reqEntity = new StringEntity(xml);
            reqEntity.setContentType("application/x-www-form-urlencoded");  // 设置类型 
            httpPost.setEntity(reqEntity);
            CloseableHttpResponse response = httpclient.execute(httpPost);
            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    System.out.println("Response content length: " + entity.getContentLength());
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(),"UTF-8"));
                    String txt;
                    while ((txt = bufferedReader.readLine()) != null) {
                        System.out.println(txt);
                        result += txt;
                    }
                }
                EntityUtils.consume(entity);
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
        logger.info("微信支付---申请退款返回报文：" + result);
        Map<String, String> xmlToMap = Xml2Map.xmlToMap(result);
        rn.setIsSuccessflag(false);
        String return_code = xmlToMap.get("return_code");
        String result_code = xmlToMap.get("result_code");
        if(return_code.equals("SUCCESS")){
            if(result_code.equals("SUCCESS")){
                rn.setIsSuccessflag(true);
                TeaOrder order = new TeaOrder();
                order.setMdf_date(new Date());
                order.setSerno(out_trade_no);
                order.setStatus("退款成功");
                order.setPayStatus("N");
                teaOrderDao.update(order);
                logger.info("申请退款成功");
            }else{
                rn.setMessage(xmlToMap.get("err_code_des"));
                logger.info("申请退款成功失败：" + xmlToMap.get("err_code_des"));
            }
        }else{
            rn.setMessage(xmlToMap.get("return_msg"));
            logger.info("申请退款成功失败：" + xmlToMap.get("return_msg"));
        }
        return rn;
    }

    @Override
    public String payRefundCallBack(HttpServletRequest request) {
        String reqXml = "<xml><return_code><![CDATA[%1$s]]></return_code><return_msg><![CDATA[%2$s]]></return_msg></xml>";
        String returnMsg = "";
        InputStream is = null;
        ByteArrayOutputStream baos = null;
        try {
            is = request.getInputStream();
            baos = new ByteArrayOutputStream();
            byte[] buff = new byte[1024];
            int length = 0;
            while ((length = is.read(buff)) != -1) {
                baos.write(buff, 0, length);
            }
            String result = new String(baos.toByteArray(), "UTF-8");
            logger.info("微信退款回调结果：" + result);
            Map<String, Object> map = WeChatUtil.xmlToMap(result);
            if ("SUCCESS".equals(map.get("result_code"))) {
                String req_info = (String) map.get("req_info");
                String data = AESUtil.encryptData(req_info, wechat.getProperty("MCH_ID"));
                logger.info("微信退款返回信息：" + data);
                returnMsg = String.format(reqXml, "SUCCESS", "OK");
            } else {
                logger.info("微信退款失败--错误信息：" + map.get("return_msg"));
                returnMsg = String.format(reqXml, "ERROR", "FAIL");
            }
        } catch (Exception e) {
            e.printStackTrace();
            returnMsg = String.format(reqXml, "ERROR", "FAIL");
        } finally {
            try {
                if (is != null)
                    is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (baos != null)
                    baos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return returnMsg;
    }

    @Override
    public Return queryRefund(String transaction_id) throws Exception {
        Return rn = new Return();
        Map<String, Object> map = new HashMap<String, Object>();
        String nonceStr = UUID.randomUUID().toString().replace("-", "").substring(0, 32);
        String appid = wechat.getProperty("APPID");
        String mch_id = wechat.getProperty("MCH_ID");
        map.put("appid", appid);// 公众账号ID
        map.put("mch_id", mch_id);// 商户号
        map.put("nonce_str", nonceStr);// 随机字符串
        map.put("sign_type", "MD5");// 签名类型 
        map.put("out_trade_no", transaction_id);// 商户订单号
        map.put("sign", WeChatUtil.getPayCustomSign(map, wechat.getProperty("KEY")));// 签名
        String xml = WeChatUtil.ArrayToXml(map);
        logger.info("微信申请退款---查询发送报文：" + xml);
        JSONObject result = WeChatUtil.sendWeChat(xml,wechat.getProperty("REFUNDQUERY"));
        logger.info("微信申请退款---查询返回报文：" + result);
        JSONObject map1 = result.getJSONObject("xml");
        if ("SUCCESS".equals(map1.get("return_code"))) {
            if("SUCCESS".equals(map1.get("result_code"))){
                rn.setMessage(map1.get("refund_status_0") + "SUCCESS—退款成功,REFUNDCLOSE—退款关闭,PROCESSING—退款处理中,CHANGE—退款异常");
            }else{
                logger.info("微信退款查询失败--错误信息：" + map1.get("err_code_des"));
                rn.setMessage(map1.get("err_code_des").toString());
            }
        } else {
            logger.info("微信退款查询失败--错误信息：" + map1.get("err_code").toString());
            rn.setMessage(map1.get("err_code").toString());
        }
        return rn;
    }
    

}
